package de.voicegym.voicegym.util.audio

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Environment
import androidx.core.content.FileProvider
import de.voicegym.voicegym.BuildConfig
import java.io.File
import java.io.InputStream

fun getDezibelFromAmplitude(amplitude: Double): Double = 20 * Math.log10(amplitude)

fun savePCMInputStreamOnSDCard(
    context: Context,
    fileName: String,
    inputStream: InputStream,
    sampleRate: Int,
    bitRate: Int
) {
    if (isExternalStorageWritable()) {
        val pcmEncoder = PCMEncoder(bitRate, sampleRate, 1)
        val outFile = getOutFile(fileName, "m4a")
        pcmEncoder.outputPath = outFile.path

        val saveFUnc = {
            pcmEncoder.prepare()
            pcmEncoder.encode(inputStream, sampleRate)
            pcmEncoder.stop()
        }

        val fileAccessUri = getFileAccessUri(context, outFile)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            context.revokeUriPermission(fileAccessUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
            saveFUnc()
        } else {
            saveFUnc()
        }
    }
}

fun getFileAccessUri(context: Context, file: File): Uri {
    return if (Build.VERSION.SDK_INT >= 24) {
        FileProvider.getUriForFile(
            context.applicationContext,
            "${BuildConfig.APPLICATION_ID}.fileprovider", file
        )
    } else {
        Uri.fromFile(file)
    }
}

/**
 * Creates a file with the current date and the given extension. If the file already exists, it is overwritten.
 * @param fileExtension: the file extension used to create the file.
 *
 * @return: created an empty File
 */
private fun getOutFile(fileString: String, fileExtension: String): File {
    val outFile = File(getVoiceGymFolder(), "$fileString.$fileExtension")
    if (outFile.exists()) outFile.delete()
    outFile.createNewFile()
    if (!outFile.canWrite()) throw Error("Cannot write file")
    return outFile
}


/* Checks if external storage is available for read and write */
fun isExternalStorageWritable(): Boolean {
    return Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED
}

/* Checks if external storage is available to at least read */
fun isExternalStorageReadable(): Boolean {
    return Environment.getExternalStorageState() in setOf(
        Environment.MEDIA_MOUNTED,
        Environment.MEDIA_MOUNTED_READ_ONLY
    )
}

private var voiceGmFolderPath: String = ""

fun initVoiceGmFolder(context: Context) {
    val externalFilesDir = context.externalCacheDir
    try {
        val file = File(externalFilesDir, "VoiceGym")
        if (file.exists() && file.isFile) {
            file.delete()
        }
        if (!file.exists()) file.mkdirs()
        voiceGmFolderPath = file.path
    } catch (ex: Throwable) {
        ex.printStackTrace()
    }
}

fun getVoiceGymFolder(): File? {
    if (voiceGmFolderPath.isEmpty())
        return null
    return File(voiceGmFolderPath)
}
